package cn.iocoder.yudao.module.trade.order.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.thirdparty.zxhx.ZXHXApiClientFactory;
import cn.iocoder.yudao.framework.thirdparty.zxhx.dto.*;
import cn.iocoder.yudao.framework.thirdparty.zxhx.enums.ZXHXMessageType;
import cn.iocoder.yudao.framework.thirdparty.zxhx.enums.ZXHXOrderStatus;
import cn.iocoder.yudao.module.api.dine.enums.DineStatusEnum;
import cn.iocoder.yudao.module.api.trade.delivery.enums.DeliveryTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderDeliveryDTO;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderCancelTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderOperateTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.delivery.dal.dataobject.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.delivery.dal.mysql.DeliveryExpressMapper;
import cn.iocoder.yudao.module.trade.order.bo.TradeOrderLogCreateBO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderDO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.order.dal.mysql.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.order.dal.mysql.TradeOrderMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.thirdparty.zxhx.ZXHXApiClientFactory.formatShipAreaId;
import static cn.iocoder.yudao.module.api.supply.ConfigConstants.SUPPLY_NAME_ZXHX;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  这里是文件说明
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/03/17
 */
@Service
@Validated
@Slf4j
public class ZXHXOrderSyncServiceImpl implements ZXHXOrderSyncService {
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderUpdateService tradeOrderUpdateService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderLogService tradeOrderLogService;

    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;
    @Resource
    private DeliveryExpressMapper deliveryExpressMapper;

    @Override
    public int autoSyncOrderInfo() {
        List<ZXHXMessagePoolRespDTO> messagePoolRespDTOS = ZXHXApiClientFactory.messageClient().getMessagePool(ZXHXMessageType.ORDER_STATUS_CHANGE, 1000);
        if (CollUtil.isEmpty(messagePoolRespDTOS)) {
            log.info("供应链({})没有新的消息", ZXHXMessageType.ORDER_STATUS_CHANGE.getName());
            return 0;
        }
        List<Integer> ids = new ArrayList<>();
        for (ZXHXMessagePoolRespDTO messagePoolRespDTO : messagePoolRespDTOS) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                log.warn("供应链同步订单信息线程休眠一定的毫秒数出错：{}", e.getMessage());
            }
            ZXHXMessageOrderStatusRespDTO messageOrderStatusRespDTO = JsonUtils.parseObject(messagePoolRespDTO.getContent(), ZXHXMessageOrderStatusRespDTO.class);
            if (messageOrderStatusRespDTO == null) {
                log.warn("供应链({})新的消息中没有解析出有效的 order_sn: {}", ZXHXMessageType.ORDER_STATUS_CHANGE.getName(), messagePoolRespDTO.getContent());
                continue;
            }
            TradeOrderDO tradeOrderDO = tradeOrderMapper.searchBySupplyRelatedNo(messageOrderStatusRespDTO.getOrderSn());
            if (tradeOrderDO == null) {
                log.warn("供应链({})新的消息中的 order_sn: {} 没有找到相关的交易订单", ZXHXMessageType.ORDER_STATUS_CHANGE.getName(), messageOrderStatusRespDTO.getOrderSn());
                continue;
            }
            if (Objects.equals(messageOrderStatusRespDTO.getOrderStatus(), ZXHXOrderStatus.AWAITING_RECEIPT.getValue())) {
                try {
                    TradeOrderDeliveryDTO dto = new TradeOrderDeliveryDTO();
                    dto.setId(tradeOrderDO.getId());
                    dto.setLogisticsId(TradeOrderDO.LOGISTICS_ID_NULL);
                    dto.setLogisticsNo("");
                    tradeOrderUpdateService.deliveryOrder(tradeOrderDO.getShopId(), dto);
                    ids.add(messagePoolRespDTO.getId());
                } catch (Exception e) {
                    log.error("供应链({})新的消息中的 order_sn: {} 同步发货信息出错", ZXHXMessageType.ORDER_STATUS_CHANGE.getName(), messageOrderStatusRespDTO.getOrderSn(), e);
                }
            } else {
                ids.add(messagePoolRespDTO.getId());
            }
            syncOrderInfoAsync(messageOrderStatusRespDTO.getOrderSn(), tradeOrderDO);
        }
        ZXHXApiClientFactory.messageClient().removeMessage(new ZXHXMessageRemoveReqDTO(ids));
        return ids.size();
    }

    @Override
    public int autoCreateOrder() {
        List<TradeOrderDO> tradeOrderDOS = tradeOrderMapper.selectWillSubmitSupplyOrders();
        if (CollUtil.isEmpty(tradeOrderDOS)) {
            log.info("[autoCreateOrder][没有需要同步创建第三方供应链订单的自有商城订单]");
            return 0;
        }
        Set<String> tradeNos = tradeOrderDOS.stream().map(TradeOrderDO::getNo).collect(Collectors.toSet());
        int count = 0;
        for (TradeOrderDO tradeOrderDO : tradeOrderDOS) {
            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderId(tradeOrderDO.getId());
            log.debug("[autoCreateOrder][需要同步创建第三方供应链订单的自有商城订单(tradeNos={})]", tradeNos);
            try {
                createOrderWhenPaid(tradeOrderDO, tradeOrderItemDOS);
                count++;
            } catch (Exception e) {
                log.error("[autoCreateOrder][需要同步创建第三方供应链订单的自有商城订单(tradeNos={})失败]", tradeNos, e);
            }
        }
        return count;
    }

    @Override
    public void createOrderWhenPaid(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
        ZXHXOrderSubmitReqDTO orderSubmitReqDTO = new ZXHXOrderSubmitReqDTO();
        orderSubmitReqDTO.setUserName(order.getReceiverName());
        orderSubmitReqDTO.setUserMobile(order.getReceiverMobile());
        orderSubmitReqDTO.setShipAreaCode(formatShipAreaId(order.getReceiverAreaId()));
        orderSubmitReqDTO.setUserAddress(order.getReceiverDetailAddress());
        orderSubmitReqDTO.setSkuList(orderItems.stream().map(item -> {
            ZXHXSkuItemReqDTO skuItemReqDTO = new ZXHXSkuItemReqDTO();
            skuItemReqDTO.setSkuId(item.getSupplyRelatedSkuId());
            skuItemReqDTO.setSkuNum(item.getCount());
            return skuItemReqDTO;
        }).toList());
        orderSubmitReqDTO.setThirdSn(order.getNo());
        if (StrUtil.isNotBlank(order.getUserRemark())) {
            orderSubmitReqDTO.setRemark(order.getUserRemark());
        }
        List<ZXHXOrderSubmitRespDTO> submitRespDTOS = ZXHXApiClientFactory.tradeClient().submitOrder(orderSubmitReqDTO);
        List<String> supplyRelatedNos = submitRespDTOS.stream().map(ZXHXOrderSubmitRespDTO::getOrderSn).collect(Collectors.toList());
        TradeOrderDO updateObj = new TradeOrderDO();
        updateObj.setId(order.getId());
        updateObj.setSupplyRelatedNos(supplyRelatedNos);
        updateObj.setSupplyRelatedOrders(JsonUtils.toJsonString(submitRespDTOS));
        tradeOrderMapper.updateById(updateObj);
    }

    @Async
    @Override
    public void syncOrderInfoAsync(String orderSn, TradeOrderDO tradeOrderDO) {
        ZXHXOrderDetailRespDTO orderDetailRespDTO = ZXHXApiClientFactory.tradeClient().getOrderDetail(orderSn);
        boolean isUpdate = false;
        TradeOrderLogCreateBO tradeOrderLogCreateBO = null;
        int beforeOrderStatus = tradeOrderDO.getStatus();
        if (orderDetailRespDTO.getOrderStatus() == ZXHXOrderStatus.AWAITING_RECEIPT.getValue()) {
            tradeOrderDO.setStatus(TradeOrderStatusEnum.DOING.getStatus());
            tradeOrderDO.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType());
            tradeOrderDO.setDeliveryTime(LocalDateTimeUtil.parse(orderDetailRespDTO.getDeliverAt(), "yyyy-MM-dd HH:mm:ss"));
            isUpdate = !Objects.equals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.DOING.getStatus());
        } else if (orderDetailRespDTO.getOrderStatus() == ZXHXOrderStatus.CONFIRM_RECEIVED.getValue()) {
            List<ZXHXOrderDetailRespDTO.OrderInfoDTO> orderInfo = orderDetailRespDTO.getOrderInfo();
            if (CollUtil.isNotEmpty(orderInfo)) {
                String expressCode = orderInfo.get(0).getExpressCode();
                DeliveryExpressDO expressDO = deliveryExpressMapper.selectBySupplyExpressCode(expressCode);
                if (expressDO == null) {
                    log.warn("[syncOrderInfoAsync][订单({}) 同步第三方订单物流信息，但是没有找到对应的快递公司({})] 即将创建之", orderSn, expressCode);
                    try {
                        expressDO = new DeliveryExpressDO();
                        expressDO.setCode(expressCode);
                        expressDO.setName(orderInfo.get(0).getExpressName());
                        expressDO.setSort(Math.toIntExact(orderInfo.get(0).getExpressId()));
                        expressDO.setSupplyName(SUPPLY_NAME_ZXHX);
                        expressDO.setSupplyRelatedId(orderInfo.get(0).getExpressId());
                        deliveryExpressMapper.insert(expressDO);
                    } catch (Exception e) {
                        log.error("[syncOrderInfoAsync][订单({}) 同步第三方订单物流信息，创建快递公司({})失败]", orderSn, expressCode, e);
                    }
                }
                if (expressDO != null) {
                    tradeOrderDO.setLogisticsId(expressDO.getId());
                    tradeOrderDO.setLogisticsNo(expressDO.getCode());
                    tradeOrderLogCreateBO = new TradeOrderLogCreateBO();
                    tradeOrderLogCreateBO.setUserId(0L);
                    tradeOrderLogCreateBO.setUserType(UserTypeEnum.ADMIN.getValue());
                    tradeOrderLogCreateBO.setOrderId(tradeOrderDO.getId());
                    tradeOrderLogCreateBO.setBeforeStatus(beforeOrderStatus);
                    tradeOrderLogCreateBO.setAfterStatus(tradeOrderDO.getStatus());
                    tradeOrderLogCreateBO.setOperateType(TradeOrderOperateTypeEnum.ADMIN_DELIVERY.getType());
                    tradeOrderLogCreateBO.setContent(TradeOrderOperateTypeEnum.ADMIN_DELIVERY.getContent().replace("{deliveryName}", expressDO.getName()).replace("{logisticsNo}", tradeOrderDO.getLogisticsNo()));
                }
                isUpdate = tradeOrderDO.getLogisticsId() == null || tradeOrderDO.getLogisticsId() == 0;
            }
        } else if (orderDetailRespDTO.getOrderStatus() == ZXHXOrderStatus.COMPLETED.getValue()
                   || orderDetailRespDTO.getOrderStatus() == ZXHXOrderStatus.REJECTED.getValue()) {
            tradeOrderDO.setStatus(TradeOrderStatusEnum.COMPLETED.getStatus());
            tradeOrderDO.setDineStatus(DineStatusEnum.ARRIVED.getValue());
            tradeOrderDO.setReceiveTime(LocalDateTimeUtil.parse(orderDetailRespDTO.getOverAt(), "yyyy-MM-dd HH:mm:ss"));
            tradeOrderLogCreateBO = new TradeOrderLogCreateBO();
            tradeOrderLogCreateBO.setUserId(0L);
            tradeOrderLogCreateBO.setUserType(UserTypeEnum.ADMIN.getValue());
            tradeOrderLogCreateBO.setOrderId(tradeOrderDO.getId());
            tradeOrderLogCreateBO.setBeforeStatus(beforeOrderStatus);
            tradeOrderLogCreateBO.setAfterStatus(tradeOrderDO.getStatus());
            tradeOrderLogCreateBO.setOperateType(TradeOrderOperateTypeEnum.SYSTEM_SUPPLY_RECEIVE.getType());
            tradeOrderLogCreateBO.setContent(TradeOrderOperateTypeEnum.SYSTEM_SUPPLY_RECEIVE.getContent());
            isUpdate = !Objects.equals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
        } else if (orderDetailRespDTO.getOrderStatus() == ZXHXOrderStatus.CANCELLED.getValue()) {
            tradeOrderDO.setStatus(TradeOrderStatusEnum.CLOSED.getStatus());
            tradeOrderDO.setCancelTime(LocalDateTimeUtil.parse(orderDetailRespDTO.getCancelAt(), "yyyy-MM-dd HH:mm:ss"));
            tradeOrderDO.setCancelType(TradeOrderCancelTypeEnum.SUPPLY_CLOSE.getType());
            tradeOrderLogCreateBO = new TradeOrderLogCreateBO();
            tradeOrderLogCreateBO.setUserId(0L);
            tradeOrderLogCreateBO.setUserType(UserTypeEnum.ADMIN.getValue());
            tradeOrderLogCreateBO.setOrderId(tradeOrderDO.getId());
            tradeOrderLogCreateBO.setBeforeStatus(beforeOrderStatus);
            tradeOrderLogCreateBO.setAfterStatus(tradeOrderDO.getStatus());
            tradeOrderLogCreateBO.setOperateType(TradeOrderOperateTypeEnum.ADMIN_CANCEL.getType());
            tradeOrderLogCreateBO.setContent(TradeOrderOperateTypeEnum.ADMIN_CANCEL.getContent());
            isUpdate = !Objects.equals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.CLOSED.getStatus());
        }
        if (!isUpdate) {
            log.info("[syncOrderInfoAsync][订单({}) 同步供应链订单({})，但是订单状态({})和本地订单状态({})一致，忽略]", tradeOrderDO.getNo(), orderSn, orderDetailRespDTO.getOrderStatus(), tradeOrderDO.getStatus());
            return;
        }
        tradeOrderMapper.updateById(tradeOrderDO);
        if (tradeOrderLogCreateBO == null) {
            return;
        }
        try {
            tradeOrderLogService.createOrderLog(tradeOrderLogCreateBO);
        } catch (Throwable ex) {
            log.error("[syncOrderInfoAsync][订单({})创建订单日志({})出错]", tradeOrderDO.getNo(), tradeOrderDO.getStatus(), ex);
        }
    }

}
